﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace SocialLotus.DAO
{
    public static class PredicateBuilder
    {
        /// <summary>
        /// Returns a predicate with the value 'true'.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Expression<Func<T, bool>> True<T>()
        {
            return f => true;
        }
        /// <summary>
        /// Returns a predicate with the value 'false'.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static Expression<Func<T, bool>> False<T>()
        {
            return f => false;
        }

        /// <summary>
        /// Combines two Expressions using the 'OR' operator.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expr1">The current expression.</param>
        /// <param name="expr2">The second expression.</param>
        /// <returns>The combined expression (OR).</returns>
        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                            Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
        }

        /// <summary>
        /// Combines two Expressions using the 'AND' operator.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="expr1">The current expression.</param>
        /// <param name="expr2">The second expression.</param>
        /// <returns>The combined expression (AND).</returns>
        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                             Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
        }
    }
}
